
package com.monlyu.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.metadata.ClassMetadata;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;

import com.monlyu.bean.Pages;
import com.monlyu.dao.Dao;
import com.monlyu.dao.SqlDao;
import com.monlyu.util.LogUtil;
import com.monlyu.util.StringUtil;

@Repository("sqlDao")
public class SqlDaoImpl extends HibernateDaoSupport implements SqlDao {

    private ThreadLocal<Session> LOCAL_SESSION = new ThreadLocal<Session>();

    private Dao dao;

    public void setDao(Dao dao){
        this.dao = dao;
    }

    @Override
    public int excute(String sql, Object... args){
        if (StringUtil.isEmpty(sql)) {
            return 0;
        }
        int refer = createQuery(sql, args).executeUpdate();
        return refer;
    }

    public String getDDL(String table){
        try {
            Query query = createQuery(table);
            List<?> values = query.list();
            if (values != null) {
                return ((Object[]) values.get(0))[1].toString();
            }
        }
        catch (Exception e) {
            LogUtil.log(SqlDaoImpl.class, e).warn("未找到表名为:" + table + "的实体");
        }
        return null;
    }

    @Override
    public List<?> find(String sql, Object... args){
        return createQuery(sql, args).list();
    }

    @Override
    public List<?> findLimit(String sql, int limit, Object... args){
        final Query query = createQuery(sql, args);
        query.setMaxResults(limit);
        return query.list();
    }

    @Override
    public ClassMetadata getClassMetadata(Class<?> clazz){
        return getSessionFactory().getClassMetadata(clazz);
    }

    @SuppressWarnings("deprecation")
    @Override
    public String[] getColumns(String sql) throws SQLException{
        Connection con = getSession().connection();
        PreparedStatement statement = con.prepareStatement(sql);
        statement.setMaxRows(1);
        final ResultSetMetaData metaData = statement.executeQuery().getMetaData();
        String[] names = new String[metaData.getColumnCount()];
        for (int i = 1; i <= metaData.getColumnCount(); i++) {
            names[i - 1] = metaData.getColumnName(i);
        }
        statement.close();
        return names;
    }

    private Query createQuery(final String queryStr, final Object... args){
        // System.out.println("修改表结构SQL: " + queryStr);
        final Query query = findSession().createSQLQuery(queryStr);
        if (args != null) {
            for (int i = 0; i < args.length; i++) {
                query.setParameter(i, args[i]);
            }
        }
        return query;
    }

    public int excuteBySql(String sql, Object[] args){
        return createQuery(sql, args).executeUpdate();
    }

    private Session findSession(){
        if (LOCAL_SESSION.get() == null) {
            LOCAL_SESSION.set(getSession());
        }
        return LOCAL_SESSION.get();
    }

    public void clearSession(){
        findSession().close();
        LOCAL_SESSION.remove();
        System.out.println("清空线程变量:" + LOCAL_SESSION.get() == null);
    }

    public Pages find(String sql, int total, int curt){
        sql = sql.trim();
        try {
            Pages pageList = new Pages(null, total, curt);
            pageList.setColumnNames(getColumns(sql));
            pageList.setTotalCount(getTotal(sql));
            SQLQuery query = getSession().createSQLQuery(sql);
            // query.setFirstResult(pageList.firstIndex());
            // query.setMaxResults(pageList.getTotalCount());
            pageList.setItems(query.list());
            return pageList;
        }
        catch (SQLException e) {
            throw new HibernateException(e);
        }
    }

    private int getTotal(String sql){
        String countSql = "";
        for (;;) {
            try {
                countSql = createCountStr(sql);
                SQLQuery query = getSession().createSQLQuery(countSql);
                List list = query.list();
                return (list == null ? new Integer(0) : (Number) list.get(0)).intValue();
            }
            catch (RuntimeException e) {
                if (countSql.length() < 18) {
                    throw e;
                }
                countSql = countSql.substring(18);
            }
        }

    }

    private String createCountStr(String str){
        String sql = str.toLowerCase();

        final int endIndex = sql.lastIndexOf("order by");
        if (endIndex > 0 && getFromPos(sql) < endIndex) {
            sql = sql.substring(0, endIndex);
        }
        return "select count(*) " + str.substring(getFromPos(sql) + 1);
    }

    private int getFromPos(String sql){
        int a = sql.indexOf(" from ");
        int b = sql.indexOf(")from ");
        return (a >= 0 && (b < 0 || a < b)) ? a : b;
    }

}
